package org.example.common.configs.mvc;

import com.alibaba.excel.exception.ExcelAnalysisException;
import com.google.common.base.Throwables;
import lombok.extern.slf4j.Slf4j;
import org.apache.xmlbeans.impl.piccolo.util.DuplicateKeyException;
import org.example.common.configs.exception.ErrorEnum;
import org.example.common.configs.exception.ServiceException;
import org.example.common.configs.exception.WGException;
import org.example.common.enums.WGErrorEnum;
import org.example.common.support.APIResponse;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
import java.util.stream.Collectors;

/**
 * @author weigang
 * @create 2022-11-10 15:14
 */
@RestControllerAdvice
@Slf4j
public class AdviceController {

    @InitBinder
    public void initBinder(WebDataBinder webDataBinder) {
        webDataBinder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
    }

    @ExceptionHandler(WGException.class)
    public APIResponse<Object> getBloomException(HttpServletRequest req, WGException e) {
        log.warn("AdviceController # getBloomException, url : [{}], raised error : [{}]", req.getRequestURI(), e.getCode());
        return APIResponse.fail(e.getCode(), e.getMessage());
    }

    @ExceptionHandler(ServiceException.class)
    public APIResponse<Object> getServiceException(HttpServletRequest req, ServiceException e) {
        log.warn("AdviceController # getServiceException, url : [{}], raised error : [{}]", req.getRequestURI(), e.getCode());
        return APIResponse.fail(e.getCode(), WGErrorEnum.parse(e.getCode()).getMsg());
    }

//    @ExceptionHandler({HystrixTimeoutException.class,
//            HystrixBadRequestException.class})
//    public APIResponse handleHystrixException(HttpServletRequest req, Exception e) {
//        log.warn("AdviceController#handleHystrixException url:{}, raised error:{}",
//                req.getRequestURI(),
//                Throwables.getStackTraceAsString(e));
//        return APIResponse.fail(ErrorEnum.e_9999);
//    }
//
//    /**
//     * HystrixCommand、feign没有fallback，会进入这里，或者fallback抛出异常
//     */
//    @ExceptionHandler(HystrixRuntimeException.class)
//    public APIResponse handleHystrixRuntimeException(HttpServletRequest req, HystrixRuntimeException e) {
//        log.warn("AdviceController#handleHystrixException url:{}, raised error, fail type:{}, err:{}",
//                req.getRequestURI(),
//                e.getFailureType(),
//                Throwables.getStackTraceAsString(e));
//
//        if (Objects.nonNull(e.getCause())) {
//            if (e.getCause() instanceof IllegalArgumentException) {
//                return APIResponse.fail(BloomErrorEnum.e_0010.getCode(), e.getCause().getMessage());
//            }
//
//            if (e.getCause() instanceof ServiceException) {
//                ServiceException se = (ServiceException) e.getCause();
//                return APIResponse.fail(se.getCode(), se.getMessage());
//            }
//        }
//
//        if (Objects.nonNull(e.getFailureType())) {
//            if (Objects.equals(e.getFailureType(), HystrixRuntimeException.FailureType.TIMEOUT)
//                    || Objects.equals(e.getFailureType(), HystrixRuntimeException.FailureType.SHORTCIRCUIT)
//                    || Objects.equals(e.getFailureType(), HystrixRuntimeException.FailureType.REJECTED_THREAD_EXECUTION)
//                    || Objects.equals(e.getFailureType(), HystrixRuntimeException.FailureType.REJECTED_SEMAPHORE_EXECUTION)
//                    || Objects.equals(e.getFailureType(), HystrixRuntimeException.FailureType.REJECTED_SEMAPHORE_FALLBACK)) {
//                return APIResponse.fail(ErrorEnum.e_0012);
//            }
//        }
//        return APIResponse.fail(ErrorEnum.e_9999);
//    }

    @ExceptionHandler(DuplicateKeyException.class)
    public APIResponse<Object> getDuplicateKeyException(HttpServletRequest req, DuplicateKeyException e) {
        log.warn("AdviceController # getDuplicateKeyException, url : [{}], raised error : [{}]", req.getRequestURI(), Throwables.getStackTraceAsString(e));
        return APIResponse.fail(WGErrorEnum.e_0028.getCode(), WGErrorEnum.e_0028.getMsg());
    }

    @ExceptionHandler(ExcelAnalysisException.class)
    public APIResponse<Object> getEasyExcelException(HttpServletRequest req, ExcelAnalysisException e) {
        log.warn("AdviceController # getEasyExcelException, url : [{}], raised error : [{}]", req.getRequestURI(), Throwables.getStackTraceAsString(e));
        if (e.getCause() instanceof WGException) {
            WGException wgException = (WGException) e.getCause();
            return APIResponse.fail(wgException.getCode(), wgException.getMessage());
        }
        return APIResponse.fail(ErrorEnum.e_9999);
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public APIResponse<Object> getMethodArgumentNotValidException(HttpServletRequest req, MethodArgumentNotValidException e) {
        String message = e.getBindingResult().getFieldErrors().stream().map(err ->
                err.getField().concat(" ").concat(err.getDefaultMessage())
        ).collect(Collectors.joining(";"));
        log.warn("AdviceController # getMethodArgumentNotValidException, url : [{}], raised error : [{}]", req.getRequestURI(), message);
        return APIResponse.fail(WGErrorEnum.e_0010.getCode(), message);
    }

    @ExceptionHandler(HttpMessageNotReadableException.class)
    public APIResponse<Object> getHttpMessageNotReadableException(HttpServletRequest req, HttpMessageNotReadableException e) {
        log.warn("AdviceController # getException, url : [{}], raised error : [{}]", req.getRequestURI(), Throwables.getStackTraceAsString(e));
        return APIResponse.fail(WGErrorEnum.e_0011.getCode(), WGErrorEnum.e_0011.getMsg());
    }

    @ExceptionHandler(Exception.class)
    public APIResponse<Object> getException(HttpServletRequest req, Exception e) {
        log.warn("AdviceController # getException, url : [{}], raised error : [{}]", req.getRequestURI(), Throwables.getStackTraceAsString(e));
        return APIResponse.fail(ErrorEnum.e_9999);
    }
}
